D:\a\csshw\csshw\src\protocol\serialization.rs
Line | Count | Source |
1 | | use windows::Win32::System::Console::{INPUT_RECORD_0, KEY_EVENT_RECORD, KEY_EVENT_RECORD_0}; |
2 | | |
3 | | use crate::protocol::{ |
4 | | ClientState, DaemonToClientMessage, FRAMED_HIGHLIGHT_LENGTH, FRAMED_INPUT_RECORD_LENGTH, |
5 | | FRAMED_KEEP_ALIVE_LENGTH, FRAMED_STATE_CHANGE_LENGTH, SERIALIZED_INPUT_RECORD_0_LENGTH, |
6 | | SERIALIZED_PID_LENGTH, TAG_HIGHLIGHT, TAG_INPUT_RECORD, TAG_KEEP_ALIVE, TAG_STATE_CHANGE, |
7 | | }; |
8 | | |
9 | | /// Serialize a [KEY_EVENT_RECORD_0] into a `Vec<u8>` using custom binary format. |
10 | | /// |
11 | | /// Returns the u16 `UnicodeChar` as `Vec<u8>`in little-endian format. |
12 | 1 | pub fn serialize_key_event_record_0(record: &KEY_EVENT_RECORD_0) -> Vec<u8> { |
13 | 1 | return unsafe { record.UnicodeChar }.to_le_bytes().to_vec(); |
14 | 1 | } |
15 | | |
16 | | /// Serialize a [KEY_EVENT_RECORD] into a `Vec<u8>`using custom binary format. |
17 | | /// |
18 | | /// Layout: [1 byte KeyDown][2 bytes RepeatCount][2 bytes VirtualKeyCode] |
19 | | /// [2 bytes VirtualScanCode][2 bytes UnicodeChar][4 bytes ControlKeyState] |
20 | 7 | pub fn serialize_key_event_record(record: &KEY_EVENT_RECORD) -> Vec<u8> { |
21 | 7 | let mut buf = Vec::with_capacity(SERIALIZED_INPUT_RECORD_0_LENGTH); |
22 | | |
23 | | // KeyDown as u8 (1 byte) |
24 | 7 | buf.push(if record.bKeyDown.as_bool() { 1u8 } else { 0u80 }); |
25 | | |
26 | | // RepeatCount as u16 LE (2 bytes) |
27 | 7 | buf.extend_from_slice(&record.wRepeatCount.to_le_bytes()); |
28 | | |
29 | | // VirtualKeyCode as u16 LE (2 bytes) |
30 | 7 | buf.extend_from_slice(&record.wVirtualKeyCode.to_le_bytes()); |
31 | | |
32 | | // VirtualScanCode as u16 LE (2 bytes) |
33 | 7 | buf.extend_from_slice(&record.wVirtualScanCode.to_le_bytes()); |
34 | | |
35 | | // UnicodeChar as u16 LE (2 bytes) |
36 | 7 | buf.extend_from_slice(&unsafe { record.uChar.UnicodeChar }.to_le_bytes()); |
37 | | |
38 | | // ControlKeyState as u32 LE (4 bytes) |
39 | 7 | buf.extend_from_slice(&record.dwControlKeyState.to_le_bytes()); |
40 | | |
41 | 7 | return buf; |
42 | 7 | } |
43 | | |
44 | | /// Serialize an [INPUT_RECORD_0].`KeyEvent` into a `Vec<u8>`using custom binary format. |
45 | | /// |
46 | | /// Panics if the [INPUT_RECORD_0] is not a `KeyEvent`. |
47 | 6 | pub fn serialize_input_record_0(record: &INPUT_RECORD_0) -> Vec<u8> { |
48 | 6 | return serialize_key_event_record(&unsafe { record.KeyEvent }); |
49 | 6 | } |
50 | | |
51 | | /// Serialize a process id into its little-endian byte representation used by |
52 | | /// the named-pipe PID handshake. |
53 | 10 | pub fn serialize_pid(pid: u32) -> [u8; SERIALIZED_PID_LENGTH] { |
54 | 10 | return pid.to_le_bytes(); |
55 | 10 | } |
56 | | |
57 | | /// Serialize a [`ClientState`] into its single-byte wire representation. |
58 | | /// |
59 | | /// # Arguments |
60 | | /// |
61 | | /// * `state` - The client state to serialize. |
62 | | /// |
63 | | /// # Returns |
64 | | /// |
65 | | /// The state's `#[repr(u8)]` discriminant, used as the payload of a tagged |
66 | | /// [`crate::protocol::TAG_STATE_CHANGE`] frame. |
67 | 16 | pub fn serialize_client_state(state: ClientState) -> u8 { |
68 | 16 | return state as u8; |
69 | 16 | } |
70 | | |
71 | | /// Serialize a highlight flag into its single-byte wire representation. |
72 | | /// |
73 | | /// # Arguments |
74 | | /// |
75 | | /// * `highlighted` - `true` if the client is the daemon's currently |
76 | | /// selected submenu client, `false` otherwise. |
77 | | /// |
78 | | /// # Returns |
79 | | /// |
80 | | /// `1` for `true`, `0` for `false`. Used as the payload of a tagged |
81 | | /// [`crate::protocol::TAG_HIGHLIGHT`] frame. |
82 | 14 | pub fn serialize_highlight(highlighted: bool) -> u8 { |
83 | 14 | return if highlighted { 15 } else { 09 }; |
84 | 14 | } |
85 | | |
86 | | /// Serialize a [`DaemonToClientMessage`] into its tagged-envelope wire |
87 | | /// representation. |
88 | | /// |
89 | | /// The first byte of the returned vector is the tag identifying the variant; |
90 | | /// the remaining bytes (if any) are the variant's payload. |
91 | | /// |
92 | | /// # Arguments |
93 | | /// |
94 | | /// * `msg` - The message to serialize. |
95 | | /// |
96 | | /// # Returns |
97 | | /// |
98 | | /// A vector containing the framed wire bytes ready to be written to the |
99 | | /// daemon's named pipe. |
100 | 13 | pub fn serialize_daemon_to_client_message(msg: &DaemonToClientMessage) -> Vec<u8> { |
101 | 13 | match msg { |
102 | 4 | DaemonToClientMessage::InputRecord(record) => { |
103 | 4 | let mut buf = Vec::with_capacity(FRAMED_INPUT_RECORD_LENGTH); |
104 | 4 | buf.push(TAG_INPUT_RECORD); |
105 | 4 | buf.extend_from_slice(&serialize_input_record_0(record)); |
106 | 4 | return buf; |
107 | | } |
108 | 2 | DaemonToClientMessage::StateChange(state) => { |
109 | 2 | let mut buf = Vec::with_capacity(FRAMED_STATE_CHANGE_LENGTH); |
110 | 2 | buf.push(TAG_STATE_CHANGE); |
111 | 2 | buf.push(serialize_client_state(*state)); |
112 | 2 | return buf; |
113 | | } |
114 | 3 | DaemonToClientMessage::Highlight(highlighted) => { |
115 | 3 | let mut buf = Vec::with_capacity(FRAMED_HIGHLIGHT_LENGTH); |
116 | 3 | buf.push(TAG_HIGHLIGHT); |
117 | 3 | buf.push(serialize_highlight(*highlighted)); |
118 | 3 | return buf; |
119 | | } |
120 | | DaemonToClientMessage::KeepAlive => { |
121 | 4 | let mut buf = Vec::with_capacity(FRAMED_KEEP_ALIVE_LENGTH); |
122 | 4 | buf.push(TAG_KEEP_ALIVE); |
123 | 4 | return buf; |
124 | | } |
125 | | } |
126 | 13 | } |